package com.game.gateway.service.account;

import java.util.Date;

import org.apache.http.Consts;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.game.common.Transmitter;
import com.game.common.constants.GlobalConstants;
import com.game.core.net.common.RemoteNode;
import com.game.core.service.PublicService;
import com.game.core.service.ServiceContainer;
import com.game.core.session.Session;
import com.game.gateway.service.server.ServerService;
import com.game.message.proto.account.AccountProtoBuf.CWAccountLoginREQ;
import com.game.message.proto.account.AccountProtoBuf.GWAccountLoginRES;
import com.game.message.proto.account.AccountProtoBuf.GWSynMoneyInfoRES;
import com.game.message.proto.account.AccountProtoBuf.WCAccountLoginRES;
import com.game.message.proto.account.AccountProtoBuf.WCSynMoneyInfoRES;
import com.game.message.proto.account.AccountProtoBuf.WGAccountLoginREQ;
import com.game.message.proto.player.PlayerProtoBuf.CWChangePlayerInfoREQ;
import com.game.message.proto.player.PlayerProtoBuf.GWChangePlayerInfoRES;
import com.game.message.proto.player.PlayerProtoBuf.WCChangePlayerInfoRES;
import com.game.message.proto.player.PlayerProtoBuf.WGChangePlayerInfoREQ;
import com.game.message.protocol.ProtocolsConfig;

public class AccountService extends PublicService
{
	private static final long serialVersionUID = 7519332241403817783L;
	private Logger logger = LoggerFactory.getLogger(AccountService.class);
	// 最近日期30天
	// private final static int RECENT_DAY = 30;
	// 最多有多少人緩存
	private final int MAX_CACHED_ACCOUNT_SIZE = 20 * 10000;
	// key为 AccountId
	public ConcurrentLinkedHashMap<String, TokenSession> tokenSessions = new ConcurrentLinkedHashMap.Builder<String, TokenSession>().maximumWeightedCapacity(MAX_CACHED_ACCOUNT_SIZE).build();
	private ConcurrentLinkedHashMap<String, Long> request_cache = new ConcurrentLinkedHashMap.Builder<String, Long>().maximumWeightedCapacity(MAX_CACHED_ACCOUNT_SIZE).build();

	private CloseableHttpAsyncClient httpAsyncClient;

	public AccountService()
	{
		httpAsyncClient = HttpAsyncClients.custom()
			.setDefaultRequestConfig(RequestConfig.custom().setSocketTimeout(3000).setConnectTimeout(3000).build())
			.setDefaultConnectionConfig(ConnectionConfig.custom().setCharset(Consts.UTF_8).build())
			.build();

		httpAsyncClient.start();
	}

	public TokenSession getTokenSession(String accountID)
	{
		return tokenSessions.get(accountID);
	}

	public RemoteNode getRemoteNode(String accountID)
	{
		TokenSession tokenSession = getTokenSession(accountID);
		RemoteNode remoteNode;
		if (tokenSession == null)
		{
			logger.debug("AccountService tokensession is null {}.", accountID);
			return null;
		}
		remoteNode = tokenSession.getSession().getRemoteNode();
		if (remoteNode == null)
		{
			logger.debug("AccountService remotenode is null {}.", accountID);
			return null;
		}
		return remoteNode;
	}

	public void login(RemoteNode node, CWAccountLoginREQ req, int callback)
	{
		logger.debug("login: client login begin. ip is " + node.getAddress().toString());
		String account = req.getAccount();
		String platform = req.getPlatform();
		int clientChannel = req.hasClientChannel() ? req.getClientChannel() : 0;
		node.setClientChannel(clientChannel);
		setTokenSession(account, node.getSession(), account);
		loginSuccess(account, platform);

	}

	private TokenSession setTokenSession(String accountID, Session session, String deviceId)
	{
		session.getRemoteNode().setAccountID(accountID);
		TokenSession tokenSession = tokenSessions.get(accountID);
		if (tokenSession == null)
		{
			tokenSession = new TokenSession(session);
			tokenSessions.put(accountID, tokenSession);
		}
		else
			tokenSession.setSession(session);

		tokenSession.setDeviceId(deviceId);
		return tokenSession;
	}

	/**
	 * 从缓存删除account的请求
	 * 
	 * @param account
	 */
	private synchronized void removeRequestCache(String account)
	{
		request_cache.remove(account);
	}

	public void setTokenSessionUserInfo(String accountID, String name, String head, String sex)
	{
		TokenSession tokenSession = tokenSessions.get(accountID);
		if (tokenSession != null)
		{
			tokenSession.setName(name);
			tokenSession.setHead(head);
			tokenSession.setSex(sex);
			tokenSession.setUserAccTime(System.currentTimeMillis());
		}
	}

	public void loginSuccess(String account, String platform)
	{
		setTokenSessionUserInfo(account + GlobalConstants.ACCOUNTID_SPLIT + platform, account, "head", "sex");
		loginSuccess(account, platform, "", account + GlobalConstants.ACCOUNTID_SPLIT + platform, "head", "sex");
	}

	public void loginSuccess(String account, String platform, String refreshToken, String name, String head, String sex)
	{
		String accountID = account;
		TokenSession tokenSession = tokenSessions.get(accountID);

		// 构造game登陆协议
		WGAccountLoginREQ.Builder sendBuilder = WGAccountLoginREQ.newBuilder();
		sendBuilder.setAccount(account);
		sendBuilder.setPlatform(platform);
		sendBuilder.setAccountID(accountID);
		sendBuilder.setRefreshToken(refreshToken);
		sendBuilder.setSessionID(0);
		sendBuilder.setPlayerIP("");
		sendBuilder.setClientChannel(0);
		sendBuilder.setDeviceId(tokenSession.getDeviceId());
		sendBuilder.setName("");
		sendBuilder.setHead("");
		sendBuilder.setSex("");
		sendBuilder.setUserinfoAccTime(tokenSession.getUserAccTime());

		ServerService service = ServiceContainer.getInstance().getPublicService(ServerService.class);
		Transmitter.getInstance().write(service.getGameNode(), GlobalConstants.DEFAULT_CALLBACK, sendBuilder.build());
	}

	public void gameLoginResult(GWAccountLoginRES message)
	{
		// 删除请求缓存
		removeRequestCache(message.getAccount());

		// 告知客户端登陆结果
		WCAccountLoginRES.Builder msg = WCAccountLoginRES.newBuilder();
//		TokenSession tokenSession = getTokenSession(message.getAccountID());
		RemoteNode remoteNode = getRemoteNode(message.getAccountID());
		remoteNode.setID(message.getID());
		if (message.getResult() == ProtocolsConfig.LOGIN_FAILED)
		{
			msg.setResult(ProtocolsConfig.LOGIN_FAILED_PLATFORM_NOTALLOW);
		}
		else if (message.getForbitTime() != null && !message.getForbitTime().equals(""))
		{
			msg.setForbitTime(message.getForbitTime());
			msg.setResult(ProtocolsConfig.LOGIN_FAILED_FORBID);
		}
		else
		{
			msg.setResult(ProtocolsConfig.LOGIN_SUCCESS);
			msg.setID(message.getID());
			msg.setAccount(message.getAccount());
			msg.setName(message.getName());
			msg.setHead("");
			msg.setSex(message.getSex());
			msg.setCard(0);
			msg.setPoints(0);
			msg.setTotal(0);
			msg.setRoom(0);
			msg.setIp("");
			msg.setRefreshToken("");
			msg.setKey(0);
			msg.setHaveNewEmail(0);
			msg.addAllWeaponInfos(message.getWeaponInfosList());
			msg.setCurrentWeaponSet(message.getCurrentWeaponSet());
			msg.addAllWeaponSetInfos(message.getWeaponSetInfosList());
			msg.setAttributeInfo(message.getAttributeInfo());
			msg.setIsNew(message.getIsNew());
			msg.setAppearance(message.getAppearance());
			msg.setMissionId(message.getMissionId());
			msg.setTeamId(message.getTeamId());
			msg.setExperience(message.getExperience());
			msg.setGoldCoin(message.getGoldCoin());
			msg.setDiamonds(message.getDiamonds());
			msg.setGiftCert(message.getGiftCert());
			msg.setFeats(message.getFeats());
			msg.addAllBuncherInfos(message.getBuncherInfosList());
			msg.addAllFashionInfos(message.getFashionInfosList());
			msg.addAllMakingInfos(message.getMakingInfosList());
			msg.addAllMissionInfos(message.getMissionInfosList());
			msg.addAllItemInfos(message.getItemInfosList());
			remoteNode.setLoginTime(new Date(message.getLonginTime()));
		}

		logger.info("GWAccountLoginRESAction account={}, card={}, points={}, room={}, id={}, ip={}",
			message.getAccountID(),
			message.getCard(),
			message.getPoints(),
			message.getRoom(),
			message.getID(),
			msg.getIp());
		Transmitter.getInstance().write(remoteNode, GlobalConstants.DEFAULT_CALLBACK, msg.build());
	}

	public void loginFailed(String account, String accountID)
	{
		// 删除请求缓存
		removeRequestCache(account);

		// 告知客户端登陆失败
		loginFailed(accountID, ProtocolsConfig.LOGIN_FAILED);
	}

	public void loginFailed(String accountID, int errorCode)
	{
		WCAccountLoginRES.Builder msg = WCAccountLoginRES.newBuilder();
		msg.setResult(errorCode);
		Transmitter.getInstance().writeAndClose(getRemoteNode(accountID), GlobalConstants.DEFAULT_CALLBACK, msg.build());
	}

	public void loginFailed(RemoteNode node)
	{
		loginFailed(node, ProtocolsConfig.LOGIN_FAILED);
	}

	public void loginFailed(RemoteNode node, int errorCode)
	{
		WCAccountLoginRES.Builder msg = WCAccountLoginRES.newBuilder();
		msg.setResult(errorCode);
		Transmitter.getInstance().writeAndClose(node, GlobalConstants.DEFAULT_CALLBACK, msg.build());
	}
	
	public void changePlayerInfo(RemoteNode node, CWChangePlayerInfoREQ req, int callback) {
		WGChangePlayerInfoREQ.Builder sendBuilder = WGChangePlayerInfoREQ.newBuilder();
		sendBuilder.setAccount(req.getAccount());
		sendBuilder.setName(req.getName());
		sendBuilder.setAppearance(req.getAppearance());
		sendBuilder.setSex(req.getSex());
		sendBuilder.setFashionInfo(req.getFashionInfo());
		ServerService service = ServiceContainer.getInstance().getPublicService(ServerService.class);
		Transmitter.getInstance().write(service.getGameNode(), GlobalConstants.DEFAULT_CALLBACK, sendBuilder.build());
	}
	
	public void changePlayerInfoResult(GWChangePlayerInfoRES res) {
		WCChangePlayerInfoRES.Builder sendBuilder = WCChangePlayerInfoRES.newBuilder();
		AccountService accountService = ServiceContainer.getInstance().getPublicService(AccountService.class);
		RemoteNode remoteNode = accountService.getRemoteNode(res.getAccount());
		sendBuilder.setAccount(res.getAccount());
		sendBuilder.setResult(res.getResult());
		sendBuilder.setExperience(res.getExperience());
		sendBuilder.setGoldCoin(res.getGoldCoin());
		sendBuilder.setDiamonds(res.getDiamonds());
		sendBuilder.setGiftCert(res.getGiftCert());
		sendBuilder.setFeats(res.getFeats());
		sendBuilder.addAllBuncherInfos(res.getBuncherInfosList());
		sendBuilder.addAllFashionInfos(res.getFashionInfosList());
		sendBuilder.addAllItemInfos(res.getItemInfosList());
		sendBuilder.addAllWeaponInfos(res.getWeaponInfosList());
		sendBuilder.addAllWeaponSetInfos(res.getWeaponSetInfosList());
		sendBuilder.setCurrentWeaponSet(res.getCurrentWeaponSet());
		Transmitter.getInstance().write(remoteNode, GlobalConstants.DEFAULT_CALLBACK, sendBuilder.build());
	}

	public void pushSynMoneyInfoResult(GWSynMoneyInfoRES res) {
		AccountService accountService = ServiceContainer.getInstance().getPublicService(AccountService.class);
		RemoteNode remoteNode = accountService.getRemoteNode(res.getAccount());
		WCSynMoneyInfoRES.Builder sendBuilder = WCSynMoneyInfoRES.newBuilder();
		sendBuilder.setAccount(res.getAccount());
		sendBuilder.setSynSource(res.getSynSource());
		sendBuilder.setExperience(res.getExperience());
		sendBuilder.setGoldCoin(res.getGoldCoin());
		sendBuilder.setDiamonds(res.getDiamonds());
		sendBuilder.setGiftCert(res.getGiftCert());
		sendBuilder.setFeats(res.getFeats());
		Transmitter.getInstance().write(remoteNode, GlobalConstants.DEFAULT_CALLBACK, sendBuilder.build());
	}
}
